/*
-----------------------------------------------------------------------------
This source file is part of SapphireEngine

SapphireEngine is a Framework for Turn Based Strategy games.
For more information see http://code.google.com/p/sapphire-engine/

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

-----------------------------------------------------------------------------
*/
#ifndef _PART_H
#define _PART_H

#include "SapphirePrerequisites.h"

#include "Core/CoreManager.h"
#include "Core/GameFactor.h"
#include "Core/PartNode.h"
#include "SapphireMemoryManager.h"

namespace SapphireEngine
{
	namespace Core
	{
		class Part
		{
		public:
			Part(int id, Ogre::String name, Ogre::String description, Ogre::String subType, Ogre::String meshFile, long hitPoints, long combatPoints)
				:mID(id),mName(name),mDescription(description),mPartSubType(subType),mMeshFile(meshFile),mHitPoints(hitPoints),mCombatPoints(combatPoints),
				mArmorFactor(getCoreManager()->getDamageTypes()), mSpeedFactor(getCoreManager()->getTerrainTypes())				
			{}
			~Part()
			{
				for(TechnologyMapIterator itr = mTechnologies.begin();itr!=mTechnologies.end();itr++)
				{
					getMemoryManager()->removePointer(itr->second);
					delete itr->second;
				}
				removePart();
			}

			//Accessors
			int getID(){return mID;}
			void setID(int id){mID=id;}

			Ogre::String getName(){return mName;}
			void setName(Ogre::String name){mName=name;}

			Ogre::String getDescriprion(){return mDescription;}
			void setDescription(Ogre::String desc){mDescription=desc;}

			Ogre::String getPartType(){return mPartType;}
			void setPartType(Ogre::String type){mPartType=type;}

			Ogre::String getPartSubType(){return mPartSubType;}
			void setPartSubType(Ogre::String subType){mPartSubType=subType;}
			
			long getHitPoints(){return mHitPoints;}
			void setHitPoints(long val){mHitPoints=val;}

			long getCombatPoints(){return mCombatPoints;}
			void setCombatPoints(long val){mCombatPoints=val;}

			Ogre::String getMeshFile(){return mMeshFile;}
			void setMeshFile(Ogre::String meshFile){mMeshFile=meshFile;}

			GameFactor* getSpeed(){return &mSpeedFactor;}
			void setSpeed(const GameFactor* speed){mSpeedFactor=*speed;}
			long getSpeedByTerrain(Ogre::String terrain){return mSpeedFactor.getByType(terrain);}
			void setSpeedByTerrain(Ogre::String terrain, long val){mSpeedFactor.setByType(terrain,val);}
			
			GameFactor* getArmor(){return &mArmorFactor;}
			void setArmor(const GameFactor* armor){mSpeedFactor=*armor;}
			long getArmorByType(Ogre::String armor){return mArmorFactor.getByType(armor);}
			void setArmorByType(Ogre::String armor, long val){mArmorFactor.setByType(armor,val);}

			void setTechnologies(TechnologyMap *techs)
			{	
				clearTechnologies();
				mTechnologies.insert(techs->begin(),techs->end());
			}
			TechnologyMap* getTechnologies()
			{
				return &mTechnologies;
			}
			void addTechnology(Technology* tech)
			{	
				mTechnologies.insert(TechnologyMapItem(tech->getID(),tech));
			}
			void clearTechnologies()
			{	
				for(TechnologyMapIterator itr = mTechnologies.begin();itr!=mTechnologies.end();itr++)
				{
					getMemoryManager()->removePointer(itr->second);
					delete itr->second;
				}
				mTechnologies.clear();
			}
			void setTechnologyLevel(int id, int level)
			{
				TechnologyMapIterator itr;
				itr = mTechnologies.find(id);
				itr->second->setLevel(level);
			}
			
			void addChildNode(PartNode *partNode)
			{
				mChildNodes.push_back(partNode);
			}
			void removeChildNode(PartNode *partNode)
			{
				if(partNode->getPart()!=0)
				partNode->getPart()->removePart();
				for(PartNodeArrayIterator itr=mChildNodes.begin(); itr!=mChildNodes.end(); itr++)
					if (*itr==partNode)
					{
						mChildNodes.erase(itr);
						getMemoryManager()->removePointer(partNode);
						delete partNode;
						break;
					}
			}
			void attachChild(PartNode* node, Part* part){node->setPart(part);}
			PartNodeArray* getChildNodes(){return &mChildNodes;}
			void setChildNodes(const PartNodeArray* nodes){mChildNodes=*nodes;}
			
		protected:
			void removePart()
			{
				while (!mChildNodes.empty())
				{
					if(mChildNodes.back()->getPart()!=0)
					{
						mChildNodes.back()->getPart()->removePart();
						getMemoryManager()->removePointer(mChildNodes.back()->getPart());
						delete mChildNodes.back()->getPart();
						mChildNodes.back()->setPart(0);
					}
					else
					{
						getMemoryManager()->removePointer(mChildNodes.back());
						delete mChildNodes.back();
						mChildNodes.pop_back();
					}
				}
			}
			int mID;
			Ogre::String mName;
			Ogre::String mDescription;
			Ogre::String mPartType;
			Ogre::String mPartSubType;
			Ogre::String mMeshFile;
			GameFactor mSpeedFactor;
			GameFactor mArmorFactor;
			long mHitPoints;
			long mCombatPoints;
			TechnologyMap mTechnologies;
			PartNodeArray mChildNodes;

		};
//------------------------------------------------------------------------------------------------------------------------------
//Part(int id, Ogre::String name, Ogre::String description, Ogre::String type, Ogre::String subType, Ogre::String meshFile, long hitPoints, long combatPoints)

		class Body : public Part
		{
		public:
			Body(int id, Ogre::String name, Ogre::String description, Ogre::String subType, Ogre::String meshFile, long hitPoints, long combatPoints)
				:Part(id,name,description,subType,meshFile,hitPoints,combatPoints)
			{
				mPartType = "Body";
			}
		protected:
		};

		class Movement : public Part
		{
		public:
			Movement(int id, Ogre::String name, Ogre::String description, Ogre::String subType, Ogre::String meshFile, long hitPoints, long combatPoints)
				:Part(id,name,description,subType,meshFile,hitPoints,combatPoints)
			{
				mPartType = "Movement";
			}
		protected:
		};

		class Weapon : public Part
		{
		public:
			Weapon(int id, Ogre::String name, Ogre::String description, Ogre::String subType, Ogre::String meshFile, long hitPoints, long combatPoints)
				:Part(id,name,description,subType,meshFile,hitPoints,combatPoints),mDamageFactor(getCoreManager()->getDamageTypes())
			{
				mPartType = "Weapon";
			}
			int getRange(){return mRange;}
			void setRange(int range){mRange = range;}

			GameFactor* getDamage(){return &mDamageFactor;}
			void setDamage(const GameFactor* damage){mSpeedFactor=*damage;}
			long getDamageByType(Ogre::String Damage){return mDamageFactor.getByType(Damage);}
			void setDamageByType(Ogre::String Damage,long val){mDamageFactor.setByType(Damage,val);}
		protected:
			int mRange;
			GameFactor mDamageFactor;
		};
	}
}

#endif

